#pragma once
#include <vector>
#include <string>
#include <functional>
#include <sys/epoll.h>
#include "Socket.hpp"

typedef std::function<void(const std::string &, std::string *resp)> Handler;

class Epoll
{
    using TcpSocket = SocketModule::TcpSocket;

public:
    Epoll()
    {
        _epollfd = epoll_create(10);
    }

    ~Epoll()
    {
        close(_epollfd);
    }

    bool Add(const TcpSocket &sock) const
    {
        int fd = sock.GetSocket();
        printf("[Epoll Add] fd = %d\n", fd);
        epoll_event ev;
        ev.data.fd = fd;
        ev.events = EPOLLIN;
        int ret = epoll_ctl(_epollfd, EPOLL_CTL_ADD, fd, &ev);
        if (ret < 0)
        {
            perror("epoll_ctl ADD");
            return false;
        }
        return true;
    }

    bool Del(const TcpSocket &sock) const
    {
        int fd = sock.GetSocket();
        printf("[Epoll_ctl] fd = %d\n", fd);
        int ret = epoll_ctl(_epollfd, EPOLL_CTL_DEL, fd, nullptr);
        if (ret < 0)
        {
            perror("epoll_ctl DEL");
            return false;
        }
        return true;
    }

    bool Wait(std::vector<TcpSocket> *output) const
    {
        output->clear();
        epoll_event events[1000];
        int nfds = epoll_wait(_epollfd, events, sizeof(events) / sizeof(events[0]), -1);
        if (nfds < 0)
        {
            perror("epoll_wait");
            return false;
        }
        for (int i = 0; i < nfds; i++)
        {
            TcpSocket sock(events[i].data.fd);
            output->push_back(sock);
        }
        return true;
    }

private:
    int _epollfd;
};

class TcpEpollServer
{
    using TcpSocket = SocketModule::TcpSocket;
public:
    TcpEpollServer(const std::string &ip, uint16_t port) : _ip(ip), _port(port) {}

    bool Start(Handler Handler)
    {
        //1、创建tcp listen_socket
        TcpSocket listen_sock;
        listen_sock.CreateTcpSocket(_port, _ip);
        Epoll epoll;
        epoll.Add(listen_sock);
        
        //2、进行事件循环监控
        for(;;)
        {
            //3、进行等待
            std::vector<TcpSocket> output;
            if(!epoll.Wait(&output))
            {
                continue;
            }
            //4、根据文件描述符的种类进行对应的处理
            for(size_t i = 0; i < output.size(); i++)
            {
                if(output[i].GetSocket() == listen_sock.GetSocket())
                {
                    TcpSocket new_sock;
                    listen_sock.AcceptConnect(&new_sock);
                }
            }
        }
        
    }
private:
    std::string _ip;
    uint16_t _port;
};